---
title: Types | Dagster
description: The Dagster type system helps you describe what kind of values your solids accept and produce.
---

# Dagster Types

The Dagster type system helps you describe what kind of values your solids accept and produce.

## Relevant APIs

| Name                                                                           | Description                                                                 |
| ------------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
| <PyObject module="dagster" object="DagsterType" />                             | Base class for dagster types.                                               |
| <PyObject module="dagster" object="PythonObjectDagsterType" />                 | A class for defining a Dagster Type whose typecheck is an isinstance check. |
| <PyObject module="dagster" object="check_dagster_type" />                      | The method to test a custom Dagster Type.                                   |
| <PyObject module="dagster" object="usable_as_dagster_type" decorator />        | A decorator to define how a Python class is used as a Dagster Type.         |
| <PyObject module="dagster" object="make_python_type_usable_as_dagster_type" /> | A method to map an existing Python type to a Dagster Type.                  |

## Overview

Each solid input and output can be annotated with a Dagster Type.

The type system:

- Is _gradual_ and _optional_. Pipelines can run without types specified explicitly, and specifying types in some places doesn't require that types be specified everywhere. Inputs and outputs default to the <PyObject module="dagster" object="Any" /> type.

- Happens at solid execution time - each type defines a `type_check_fn` that knows how to check whether values match what it expects. When a type is specified for a solid's input, then the type check occurs immediately before the solid is executed. When a type is specified for a solid's output, then the type check occurs immediately after the solid is executed.

- Is complimentary to the [PEP 484](https://www.python.org/dev/peps/pep-0484/) Python type system. PEP 484 annotations enable static checks that verify variables and return values match particular Python types, while the Dagster type system enables runtime checks that include arbitrary validation logic.

---

## Defining a Dagster Type

The core API for defining Dagster types is <PyObject module="dagster" object="DagsterType" />.

```python file=/concepts/types/types.py startafter=start_basic_even_type endbefore=end_basic_even_type
EvenDagsterType = DagsterType(
    name="EvenDagsterType",
    type_check_fn=lambda _, value: isinstance(value, int) and value % 2 is 0,
)
```

Once created, types can be attached to solid <PyObject module="dagster" object="InputDefinition" pluralize /> and <PyObject module="dagster" object="OutputDefinition" pluralize />.

```python file=/concepts/types/types.py startafter=start_basic_even_type_no_annotations endbefore=end_basic_even_type_no_annotations
@solid(
    input_defs=[InputDefinition("num", EvenDagsterType)],
    output_defs=[OutputDefinition(EvenDagsterType)],
)
def double_even(_, num):
    return num
```

The type system truly shines once the type check expresses richer behavior, such as column-level schema on a dataframe. For example, check out the [Validating Pandas DataFrames with Dagster Types](/integrations/pandas) guide.

## Dagster Types Inferred from Type Hints

If a Python input or output has a PEP 484 type annotation, and a DagsterType is
not provided on the corresponding input or output definition, then Dagster will automatically
generate a DagsterType that corresponds to the annotated Python type.

In this example, the defined solid will end up with a DagsterType named "MyClass" that:

- Shows up in Dagit in the representation of the solid.
- Is checked at runtime on the value returned by the solid.

```python file=/concepts/types/types.py startafter=start_auto_type endbefore=end_auto_type
class MyClass:
    pass


def my_solid(_) -> MyClass:
    return MyClass()
```

If the solid in the above example returned an object that was not an instance of MyClass, Dagster
would raise an error after executing the solid.

## Built-in Types

Here is a list of Dagster's built-in Dagster types. You can find code examples of each type's usage in its API Reference:

- <PyObject module="dagster" object="Any" />: Use this type for any input,
  output, or config field whose type is unconstrained.
- <PyObject module="dagster" object="Bool" />: Use this type for any boolean
  input, output, or config_field.
- <PyObject module="dagster" object="Int" />: Use this type for any integer
  input or output.
- <PyObject module="dagster" object="Float" />: Use this type for any float
  input, output, or config value.
- <PyObject module="dagster" object="String" />: Use this type for any string
  input, output, or config value.
- <PyObject module="dagster" object="Optional" />: Use this type only for inputs
  and outputs, if the value can also be None.
- <PyObject module="dagster" object="List" />: Use this type for inputs, or
  outputs.
- <PyObject module="dagster" object="Dict" />: Use this type for inputs, or
  outputs that are dicts.
- <PyObject module="dagster" object="Set" />: Use this type for inputs, or
  outputs that are sets.
- <PyObject module="dagster" object="Tuple" />: Use this type for inputs or
  outputs that are tuples.
- <PyObject module="dagster" object="Nothing" />: Use this type only for inputs
  and outputs, in order to establish an execution dependency without
  communicating a value.

  See details in the [Nothing dependencies](/concepts/solids-pipelines/pipelines#order-based-dependencies-nothing-dependencies) example.

## Testing a Dagster Type

You can use <PyObject module="dagster" object="check_dagster_type" /> to test the type check function of a custom Dagster Type:

```python file=/concepts/types/types.py startafter=start_test_dagster_type endbefore=end_test_dagster_type
from dagster import check_dagster_type, Dict, Any


def test_dagster_type():

    assert check_dagster_type(Dict[Any, Any], {"foo": "bar"}).success
```

## Examples

### Using Dagster Types with PEP 484 Type Annotations

Dagster types peacefully coexist with Python type annotations. In this example, the inputs and
outputs of the solid compute function are integers, and the type check function for
`EvenDagsterType` will be invoked at runtime to verify that they are even.

```python file=/concepts/types/types.py startafter=start_basic_even_type_with_annotations endbefore=end_basic_even_type_with_annotations
@solid(
    input_defs=[InputDefinition("num", EvenDagsterType)],
    output_defs=[OutputDefinition(EvenDagsterType)],
)
def double_even_with_annotations(_, num: int) -> int:
    return num
```

## Patterns

### Associating Dagster Types with Python Types

As mentioned earlier, any Python type used to annotate an argument or return value of solid-decorated
function has a corresponding Dagster type that will be used for the corresponding input or output
definition.

By default, Dagster will generate Dagster types for Python types that it's not aware of, but you can
also explicitly control the Dagster type that will be used for a particular Python type.

There are two APIs:

- <PyObject module="dagster" object="usable_as_dagster_type" decorator /> for direct
  annotations of class declarations.
- <PyObject module="dagster" object="make_python_type_usable_as_dagster_type" /> for
  mapping existing classes.

This is designed for importing python types libraries that cannot be altered and mapping them to Dagster types.

#### Decorating class declarations

```python file=/concepts/types/usable_as.py
from dagster import solid, usable_as_dagster_type


@usable_as_dagster_type
class EvenType:
    def __init__(self, num):
        assert num % 2 is 0
        self.num = num


@solid
def double_even(_, even_num: EvenType) -> EvenType:
    return EvenType(even_num.num * 2)
```

#### Mapping existing classes

```python file=/concepts/types/make_usable.py
from dagster import PythonObjectDagsterType, make_python_type_usable_as_dagster_type, solid


class EvenType:
    def __init__(self, num):
        assert num % 2 is 0
        self.num = num


EvenDagsterType = PythonObjectDagsterType(EvenType, name="EvenDagsterType")

make_python_type_usable_as_dagster_type(EvenType, EvenDagsterType)


@solid
def double_even(_, even_num: EvenType) -> EvenType:
    return EvenType(even_num.num * 2)
```

However, this approach does have downsides. Importing these types will causes a global side effect as there is an internal registry which manages these types. This can introduce challenges in terms of testability and also can cause changes in behavior based on import order.

Additionally some of the most useful patterns in the ecosystem are to use type factories to programmatically create Dagster types, such as in our dagster-pandas module. In these cases a 1:1 mapping between dagster type and python type _no longer exists_. E.g. in dagster-pandas the python representation for all the dataframe variants is simply _pandas.DataFrame_.

For clearly scoped business objects, the reduction in boilerplate is significant and eases mypy compliance, hence its inclusion in the public Dagster API.

We do _not_ recommend that libraries use this pattern and instead rely on other techniques to achieve mypy compliance.
